package com.firemoss.atonement.metadata.inspectors.property
{
	import com.firemoss.atonement.metadata.Property;
	import com.firemoss.atonement.metadata.PropertyMetadata;
	import org.as3commons.lang.ClassUtils;
	import org.as3commons.reflect.Accessor;
	import org.as3commons.reflect.AccessorAccess;
	import org.as3commons.reflect.Field;
	import org.as3commons.reflect.MetaData;
	import org.as3commons.reflect.MetaDataArgument;
	import org.as3commons.reflect.MetadataUtils;
	import org.as3commons.reflect.Type;
	import org.as3commons.reflect.Variable;

	public class DefaultPropertyInspector implements IPropertyInspector
	{

		//----------------------------------------------------------
		// Public Methods 
		//----------------------------------------------------------

		public function inspect( clazz : Class ) : PropertyMetadata
		{
			var type : Type = Type.forClass( clazz );
			var result : PropertyMetadata = new PropertyMetadata( type )

			for each ( var field : Field in type.properties )
			{
				// "prototype" isn't a property we want to muck with
				if ( field.declaringType.name != "Class" )
				{
					var property : Property = new Property()
					property.name = field.name
					property.type = field.type;

					if ( field is Accessor )
					{
						property.writeable = Accessor( field ).writeable
						property.readable = Accessor( field ).readable
					}

					for each ( var meta : MetaData in field.metaData )
					{
						if ( meta.name == "Ignore" )
						{
							property.ignored = true
						}

						if ( meta.name == "CollectionOf" )
						{
							if ( meta.arguments.length == 0 || MetaDataArgument( meta.arguments[ 0 ]).value == null )
							{
								throw new Error( "Error inspecting " + type.fullName + ". Please format your [CollectionOf] annotation in the form [CollectionOf(\"your.package.and.Class\")]" );
							}

							property.collectionOf = ClassUtils.forName( meta.arguments[ 0 ].value );
						}

						if ( meta.name == "PropertyResolver" )
						{
							var prArgs : Object = {}
							for each ( var item : MetaDataArgument in meta.arguments )
							{
								prArgs[ item.key ] = item.value
							}

							if ( prArgs.hasOwnProperty( "type" ))
							{
								var resolverClass : Class = ClassUtils.forName( prArgs.type );
							}
							else
							{
								throw new Error( "Please state a type for your [PropertyResolver]." );
							}

							var resolverInstance : Object = new resolverClass()

							if ( !resolverInstance.hasOwnProperty( prArgs.functionName ))
							{
								throw new Error( "The desired resolver class, " + Type.forClass( resolverClass ).fullName + ", doesn't have an accessible instance (not static!) function named " + prArgs.functionName );
							}

							property.valueResolutionFunction = resolverInstance[ meta.arguments[ 1 ].value ]

							if ( prArgs.hasOwnProperty( "sourcePropertyName" ))
							{
								property.sourcePropertyName = prArgs.sourcePropertyName
							}
						}
					}

					result.addProperty( property );
				}

			}

			return result;
		}
	}
}
